package rgroupcontroller

import (
	"context"
	"encoding/json"
	"fmt"
	"vpn-management-server/logger"
	"vpn-management-server/network"
	"vpn-management-server/security/code"
	"vpn-management-server/src/dao/rgroupdao"
	"vpn-management-server/src/dao/ruledao"
	"vpn-management-server/src/model/rgroupmodel"
	"vpn-management-server/src/model/rulemodel"
	"vpn-management-server/src/service/rgroupservice"
	"vpn-management-server/src/service/ruleservice"
)

// AddRGroup 添加规则组 既可以是超级/规则管理员添加 也可以是用户组管理员添加
// 用户组管理员添加的话ug_id = 管理用户组的ID 其他管理员添加 设置为-1
func AddRGroup(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if rgroup, ok := request.GetModel().(*rgroupmodel.RGroup); ok {
		if !rgroupdao.HasRuleGroup(rgroup.Name, rgroup.UGroupID) {
			id, err := rgroupdao.AddRGroup(rgroup)
			if err != nil || id == -1 {
				logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "add rgroup fail,err", err)
				response.Code = code.BAD_REQUEST
				response.ErrorMsg = "add rgroup fail"
				return
			}
			response.Code = code.SUCCESS
			rgroup.ID = int(id)
			resData, _ := json.Marshal(&rgroup)
			response.Data = resData
			logger.Logger.Infof("add rgroup %s success\n", rgroup.Name)
		} else {
			logger.Logger.ErrorfWithConn(ctx.Value("conn_id").(string), "rgroup %s exist\n", rgroup.Name)
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = "rgroup exist"
			return
		}
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to rgroup fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to rgroup fail"
	}
}

// GetRGroupsByPage 超级管理员/规则管理员 分页获取规则组 UGroupID传入-1 用户组管理员获取规则组 UGroupID传入用户组ID
func GetRGroupsByPage(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if RGroupGet, ok := request.GetModel().(*rgroupmodel.GetRGroup); ok {
		var resData = struct {
			RGroups []*rgroupmodel.RGroup
			Count   int
		}{}
		// 分页获取用户组规则
		rgroups := rgroupdao.GetRGroupsByPage(RGroupGet.PageSize, RGroupGet.PageNo, RGroupGet.UGroupID)
		count := rgroupdao.GetRGroupsCount(RGroupGet.UGroupID)
		if count == -1 {
			logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "get rgroups by page fail")
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = "get rgroup by page fail"
			return
		}
		if count == 0 {
			logger.Logger.Warn("rule group is empty")
		}
		resData.RGroups = rgroups
		resData.Count = count
		data, _ := json.Marshal(resData)
		response.Data = data
		response.Code = code.SUCCESS
		logger.Logger.Info("get rgroup by page success\n")
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to GetRGroup fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to GetRGroup fail"
	}
}

// DeleteRGroups 删除规则组
func DeleteRGroups(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if RGroupInfo, ok := request.GetModel().(*rgroupmodel.RGroupInfo); ok {
		err := rgroupservice.DeleteRGroupsService(RGroupInfo.ID)
		if err != nil {
			logger.Logger.ErrorfWithConn(ctx.Value("conn_id").(string), err.Error())
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = err.Error()
			return
		}
		response.Code = code.SUCCESS
		logger.Logger.Infof("delete rgroups %s success\n", RGroupInfo.Name)
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to RGroupInfo fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to RGroupInfo fail"
	}
}

// GrantRGroupToUGroup 规则/规则管理员给用户组授予规则组 授予的同时给用户组属于规则组中的规则 这样做是为了方便用户组管理员删除规则
func GrantRGroupToUGroup(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if GrantUGroup, ok := request.GetModel().(*rgroupmodel.GrantUGroup); ok {
		// 根据规则组ID获取里面所有的规则id
		RIDs := ruleservice.GetRuleIDsByRGroupIDService(GrantUGroup.RGroupID)
		// 根据用户组ID获取改用户组已分配的所有规则
		rules := ruledao.GetUGroupRules(GrantUGroup.UGroupID)
		// 比较两者是否有重复之处
		if IDs := ruleservice.CompareRulesListService(rules, RIDs); len(IDs) > 0 {
			logger.Logger.ErrorfWithConn(ctx.Value("conn_id").(string), "ugroup rule %v exist\n", IDs)
			response.Code = code.FORBIDDEN
			response.ErrorMsg = "ugroup id exist"
			response.Header["IDs"] = IDs
			return
		}
		// 分配规则组给用户组
		err := rgroupservice.GrantRGroupToUGroupService(GrantUGroup.RGroupID, GrantUGroup.UGroupID, GrantUGroup.Signer)
		if err != nil {
			logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "grant rgroup to user group fail")
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = "grant rgroup to user group fail"
			return
		}
		response.Code = code.SUCCESS
		logger.Logger.Info("grant rgroup to user group success")
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to GrantUGroup fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to GrantUGroup fail"
	}
}

// DepriveRGroupFromUGroup 取消用户组的规则组 超级管理员/规则管理员可用 TODO
func DepriveRGroupFromUGroup(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if DepriveUGroup, ok := request.GetModel().(*rgroupmodel.DepriveUGroup); ok {
		err := rgroupservice.DepriveRGroupFromUGroupService(DepriveUGroup.RGroupID, DepriveUGroup.UGroupID)
		if err != nil {
			logger.Logger.ErrorfWithConn(ctx.Value("conn_id").(string), "delete user group DepriveUGroup fail")
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = "delete ugroup rgroups fail"
			return
		}
		response.Code = code.SUCCESS
		logger.Logger.Info("delete ugroup rgroups success")
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to DepriveUGroup fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to DepriveUGroup fail"
	}
}

// DeleteUGroupRGroups 用户组管理员删除用户组规则组
func DeleteUGroupRGroups(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if RGroupInfo, ok := request.GetModel().(*rgroupmodel.RGroupInfo); ok {
		err := rgroupservice.DeleteRGroupsFromUGroupService(RGroupInfo.ID)
		if err != nil {
			logger.Logger.ErrorfWithConn(ctx.Value("conn_id").(string), "delete user group rgroups fail")
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = "delete user group rgroups fail"
			return
		}
		response.Code = code.SUCCESS
		logger.Logger.Info("delete user group rgroups success")
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to RGroupInfo fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to RGroupInfo fail"
	}
}

// GrantRGroupToUser 用户组管理员分配规则组给用户
func GrantRGroupToUser(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if GrantUser, ok := request.GetModel().(*rgroupmodel.GrantUser); ok {
		if rgroupdao.HasUserRGroup(GrantUser.RGroupID, GrantUser.UserID) {
			logger.Logger.ErrorfWithConn(ctx.Value("conn_id").(string), "rule group %d exist", GrantUser.RGroupID)
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = fmt.Sprintf("rule group %d exist", GrantUser.RGroupID)
			return
		}

		err := rgroupdao.GrantRGroupToUser(GrantUser.RGroupID, GrantUser.UserID, GrantUser.Signer)
		if err != nil {
			logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "grant rgroup to user fail")
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = "grant rgroup to user fail"
			return
		}
		response.Code = code.SUCCESS
		logger.Logger.Info("grant rgroup to user success")
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to GrantUser fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to GrantUser fail"
	}
}

// DepriveRGroupFromUser 用户组管理员取消分配给用户的规则组
func DepriveRGroupFromUser(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if DepriveUser, ok := request.GetModel().(*rgroupmodel.DepriveUser); ok {
		err := rgroupdao.DepriveRGroupFromUser(DepriveUser.RGroupID, DepriveUser.UserID)
		if err != nil {
			logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "deprive rgroup from user fail")
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = "deprive rgroup from user fail"
			return
		}
		RIDs := ruleservice.GetRuleIDsByRGroupIDService(DepriveUser.RGroupID)
		err = ruledao.DepriveRuleFromUser(RIDs, DepriveUser.UserID)
		if err != nil {
			logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "deprive rule from user fail")
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = "deprive rule from user fail"
			return
		}
		response.Code = code.SUCCESS
		logger.Logger.Info("deprive rgroup from user success")
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to DepriveUser fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to DepriveUser fail"
	}
}

// GrantRuleToRGroup 管理员分配规则给规则组 超级/规则/用户组管理员都可以用
func GrantRuleToRGroup(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if GrantRGroup, ok := request.GetModel().(*rgroupmodel.GrantRule); ok {
		rules := ruleservice.GetRulesByRGroupIDService(GrantRGroup.RGroupID)
		if IDs := ruleservice.CompareRulesListService(rules, GrantRGroup.IDs); len(IDs) > 0 {
			logger.Logger.ErrorfWithConn(ctx.Value("conn_id").(string), "rule %v exist\n", IDs)
			response.Code = code.FORBIDDEN
			response.ErrorMsg = "rule exist"
			response.Header["IDs"] = IDs
			return
		}
		err := rgroupdao.GrantRuleToRGroup(GrantRGroup.IDs, GrantRGroup.RGroupID, GrantRGroup.Signer)
		if err != nil {
			logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "grant rule to rgroup fail")
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = "grant rule to rgroup fail"
			return
		}
		response.Code = code.SUCCESS
		logger.Logger.Info("grant rule to rgroup success")
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to GrantRGroup fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to GrantRGroup fail"
	}
}

// DepriveRuleFromRGroup 管理员取消分配给规则组的规则 超级/规则/用户组管理员都可以用
func DepriveRuleFromRGroup(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if DepriveUser, ok := request.GetModel().(*rgroupmodel.DepriveRule); ok {
		err := rgroupdao.DepriveRuleFromRGroup(DepriveUser.IDs, DepriveUser.RGroupID)
		if err != nil {
			logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "deprive rule from rgroup fail")
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = "deprive rule from rgroup fail"
			return
		}
		response.Code = code.SUCCESS
		logger.Logger.Info("deprive rule from rgroup success")
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to DepriveRGroup fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to DepriveRGroup fail"
	}
}

// GetRGroupRuleInfos 根据规则组ID获取规则组内所有的规则信息
func GetRGroupRuleInfos(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if RGroupInfo, ok := request.GetModel().(*rgroupmodel.RGroupInfo); ok {
		ruleInfos := ruleservice.GetRuleInfosByRGroupIDService(RGroupInfo.ID)
		if ruleInfos == nil {
			logger.Logger.Warn("rgroup not have rules")
			ruleInfos = []*rulemodel.RuleInfo{}
		}
		data, _ := json.Marshal(ruleInfos)
		response.Data = data
		response.Code = code.SUCCESS
		logger.Logger.Info("get rule info by rgid success")
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to RGroupInfo fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to RGroupInfo fail"
	}
}

// GetUserRGroupByPage 分页获取用户的规则组信息
func GetUserRGroupByPage(ctx context.Context, request *network.NetRequest, response *network.NetResponse) {
	if GetUserRGroup, ok := request.GetModel().(*rgroupmodel.GetUserRGroup); ok {
		var resData = struct {
			RGroup []*rgroupmodel.RGroup
			Count  int
		}{}
		// 分页获取用户组规则
		rgroups := rgroupdao.GetUserRGroupsByPage(GetUserRGroup.PageSize, GetUserRGroup.PageNo, GetUserRGroup.UserID)
		count := rgroupdao.GetUserRGroupCount(GetUserRGroup.UserID)
		if count == -1 {
			logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "get user rgroup by page fail")
			response.Code = code.BAD_REQUEST
			response.ErrorMsg = "get user rgroup by page fail"
			return
		}
		if rgroups == nil {
			logger.Logger.Warn("user rgroup is empty")
			rgroups = []*rgroupmodel.RGroup{}
		}
		resData.RGroup = rgroups
		resData.Count = count
		data, _ := json.Marshal(resData)
		response.Data = data
		response.Code = code.SUCCESS
		logger.Logger.Info("user rgroup by page success")
	} else {
		logger.Logger.ErrorWithConn(ctx.Value("conn_id").(string), "Transform interface to GetUserRGroup fail")
		response.Code = code.BAD_REQUEST
		response.ErrorMsg = "transform interface to GetUserRGroup fail"
	}
}
